
module ControlledVisit
(
        Info(..),
        getInfo,
        getUsefulContents,
        isDirectory
) where




import System.Directory (Permissions(..), getModificationTime, getPermissions)
import System.FilePath (takeExtension)
import Data.Time.Clock (UTCTime(..))
import System.Directory (doesDirectoryExist, getDirectoryContents)
import System.FilePath ((</>))
import Control.Exception (bracket, handle, SomeException)


import Control.Monad (filterM, liftM, forM)
import System.IO (IOMode(..), hClose, hFileSize, openFile)



data Info = Info {
      infoPath :: FilePath
    , infoPerms :: Maybe Permissions
    , infoSize :: Maybe Integer
    , infoModTime :: Maybe UTCTime
    } deriving (Eq, Ord, Show)

returnnothing :: SomeException -> IO (Maybe a)
returnnothing _ = return Nothing

maybeIO :: IO a -> IO (Maybe a)
--maybeIO act = handle (\_ -> return Nothing) (Just `liftM` act)
maybeIO act = handle returnnothing (liftM Just act)

getInfo :: FilePath -> IO Info
getInfo path = do
  perms <- maybeIO (getPermissions path)
  size <- maybeIO (bracket (openFile path ReadMode) hClose hFileSize)
  modified <- maybeIO (getModificationTime path)
  return (Info path perms size modified)

traverse1 :: ([Info] -> [Info]) -> FilePath -> IO [Info]

traverse1 order path = do
    names <- getUsefulContents path
    contents <- mapM getInfo (path : map (path </>) names)
    liftM concat $ forM (order contents) $ \info -> do
      if isDirectory info && infoPath info /= path
        then traverse1 order (infoPath info)
        else return [info]

getUsefulContents :: FilePath -> IO [String]
getUsefulContents path = do
    names <- getDirectoryContents path
    return (filter (`notElem` [".", ".."]) names)

isDirectory :: Info -> Bool
isDirectory = maybe False searchable . infoPerms








